#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "char_device"
#define CLASS_NAME "char_device"

#define DEVICE_NUMBER 1 //定义次设备号的个数
#define BASE_MINOR 0 // 定义次设备号起始地址
#define STATIC_MAJOR 240 // 静态分配的主设备号

static dev_t dev_number; // 设备号（主次设备号组合）
static struct cdev example_cdev; // 字符设备结构体
static struct class *example_class; // 类结构，用于自动创建设备节点
static struct device *example_device; // 设备结构
static char message[256] = "Hello from kernel!\n";
static int device_open = 0;


// 定义模块参数 ，控制主设备号的分配方式
static int major_allo = 0;             // 设置为 1 使用静态分配，0 使用动态分配，默认值为 0 
module_param(major_allo, int, 0444);    // 参数名为 myint，类型为 int，权限为只读
MODULE_PARM_DESC(major_allo, "major allo mode parameter");

// 打开设备
static int dev_open(struct inode *inodep, struct file *filep) {
    if (device_open)
        return -EBUSY; // 如果设备已打开，返回忙状态
    device_open++;
    printk(KERN_INFO "Device opened\n");
    return 0;
}

// 关闭设备
static int dev_release(struct inode *inodep, struct file *filep) {
    device_open--;
    printk(KERN_INFO "Device closed\n");
    return 0;
}

// 读取设备
static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset) {
    size_t msg_len = strlen(message);

    if (*offset >= msg_len)
        return 0; // 已经到达 EOF，返回 0

    // 计算读取的实际长度
    size_t bytes_to_read = min(len, msg_len - *offset);

    // 将数据复制到用户空间
    if (copy_to_user(buffer, message + *offset, bytes_to_read))
        return -EFAULT;

    *offset += bytes_to_read; // 更新偏移量
    return bytes_to_read;     // 返回读取的字节数
}

// 写入设备
static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset) {
    size_t max_len = sizeof(message) - 1; // 留出空间给末尾的 '\0'

    // 如果写入数据超出缓冲区大小，截断
    size_t bytes_to_write = min(len, max_len);

    if (copy_from_user(message, buffer, bytes_to_write))
        return -EFAULT;

    message[bytes_to_write] = '\0'; // 确保字符串以 '\0' 结尾
    printk(KERN_INFO "Received from user: %s\n", message);
    return bytes_to_write; // 返回写入的字节数
}

static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = dev_open,
    .release = dev_release,
    .read = dev_read,
    .write = dev_write,
};

// 模块初始化函数
static int __init example_init(void) {
    int ret;

    // 1. 分配设备号
    if (major_allo)
    {
        dev_number = MKDEV(STATIC_MAJOR, 0); // 创建主设备号和次设备号
        ret = register_chrdev_region(dev_number, DEVICE_NUMBER, DEVICE_NAME); // 静态分配设备号
        if (ret < 0) {
            printk(KERN_ALERT "Failed to register static major number %d\n", STATIC_MAJOR);
            return ret;
        }
        printk(KERN_ALERT "static alloc major number\n");
    }
    else
    {
        ret = alloc_chrdev_region(&dev_number, BASE_MINOR, DEVICE_NUMBER, DEVICE_NAME); // 动态分配设备号
        if (ret < 0) {
            printk(KERN_ALERT "Failed to allocate dynamic major number\n");
            return ret;
        }
        printk(KERN_ALERT "dynamic alloc major number\n");
    }


    // 2. 初始化字符设备
    cdev_init(&example_cdev, &fops);
    example_cdev.owner = THIS_MODULE;

    // 3. 添加字符设备到系统
    ret = cdev_add(&example_cdev, dev_number, DEVICE_NUMBER);
    if (ret < 0) {
        unregister_chrdev_region(dev_number, DEVICE_NUMBER);
        printk(KERN_ALERT "Failed to add cdev\n");
        return ret;
    }

    // 4. 创建设备节点

    // 创建类
    example_class = class_create(THIS_MODULE, CLASS_NAME);
    if (IS_ERR(example_class)) {
        cdev_del(&example_cdev);
        unregister_chrdev_region(dev_number, DEVICE_NUMBER);
        printk(KERN_ALERT "Failed to create device class\n");
        return PTR_ERR(example_class);
    }

    // 创建设备节点
    example_device = device_create(example_class, NULL, dev_number, NULL, DEVICE_NAME);
    if (IS_ERR(example_device)) {
        class_destroy(example_class);
        cdev_del(&example_cdev);
        unregister_chrdev_region(dev_number, DEVICE_NUMBER);
        printk(KERN_ALERT "Failed to create device\n");
        return PTR_ERR(example_device);
    }
    printk(KERN_INFO "Device registered with major number %d and minor number %d\n",
           MAJOR(dev_number), MINOR(dev_number));
    return 0;
}

// 模块清理函数
static void __exit example_exit(void) {
    device_destroy(example_class, dev_number); // 销毁设备
    class_destroy(example_class);             // 销毁类
    cdev_del(&example_cdev);                  // 删除字符设备
    unregister_chrdev_region(dev_number, DEVICE_NUMBER); // 注销设备号
    printk(KERN_INFO "Device unregistered\n");
}

module_init(example_init);
module_exit(example_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A character device driver with major and minor numbers");
MODULE_VERSION("1.0");
